﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Xml;
using ALinq.Access;
using ALinq.Mapping;
using ALinq.SQLite;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NorthwindDemo;

namespace TestProject
{
    [TestClass]
    public class DatabaseMappingTest
    {
        private const string DatabaseName = "NorthwindDatabase";
        class NorthwindMappingSource : FluentMappingSource
        {
            public NorthwindMappingSource(Action<DatabaseMapping<NorthwindDatabase>> func = null)
            {
                Map<NorthwindDatabase>(mapping =>
                {
                    mapping.ProviderType = typeof(SQLiteProvider);
                    mapping.Name = DatabaseName;

                    if (func != null)
                        func(mapping);
                });
            }
        }


        [TestMethod]
        public void TestDatabaseName()
        {
            var mappingSource = new NorthwindMappingSource();
            var model = mappingSource.GetModel(typeof(NorthwindDatabase));
            Assert.IsNotNull(model);
            Assert.AreEqual(DatabaseName, model.DatabaseName);
            Assert.AreEqual(typeof(SQLiteProvider), model.ProviderType);
        }

        [TestMethod]
        public void ChangeDatabaseName()
        {
            var mappingSource = new NorthwindMappingSource(mapping =>
            {
                mapping.Name = "NewDatabaseName";
            });
            var model = mappingSource.GetModel(typeof(NorthwindDatabase));
            Assert.AreEqual("NewDatabaseName", model.DatabaseName);
        }

        [TestMethod]
        public void ChangeProvider()
        {
            var mappingSource = new NorthwindMappingSource(mapping =>
            {
                mapping.ProviderType = typeof(AccessDbProvider);
            });
            var model = mappingSource.GetModel(typeof(NorthwindDatabase));
            Assert.AreEqual(typeof(AccessDbProvider), model.ProviderType);

        }

        [TestMethod]
        public void NewInstance()
        {
            var mappingSource = new FluentMappingSource();
            mappingSource.Map<NorthwindDatabase>(mapping =>
            {
                mapping.ProviderType = typeof(AccessDbProvider);
            });
            var model = mappingSource.GetModel(typeof(NorthwindDatabase));
            Assert.AreEqual(typeof(AccessDbProvider), model.ProviderType);
        }

        [TestMethod]
        public void NewDatabaseMapping()
        {
            DatabaseMapping databaseMapping;
            TableMapping tableMapping;
            ColumnMapping columnMapping;
            PropertyInfo[] columnProperties;
            PropertyInfo associationProperty;
            AssociationMapping associationMapping;

            databaseMapping = new DatabaseMapping(typeof(NorthwindDatabase));
            tableMapping = new TableMapping(typeof(Category)) { Name = "Categories" };
            databaseMapping.Tables.Add(tableMapping);

            columnProperties = new[] { 
                typeof(Category).GetProperty("CategoryID"), 
                typeof(Category).GetProperty("CategoryName"),
                typeof(Category).GetProperty("Description"), 
                typeof(Category).GetProperty("Picture"),
            };
            associationProperty = typeof(Category).GetProperty("Products");
            foreach (var property in columnProperties)
            {
                columnMapping = new ColumnMapping(property);
                tableMapping.RowType.Columns.Add(columnMapping);
            }

            associationMapping = new AssociationMapping(associationProperty);
            associationMapping.ThisMember = new[] { typeof(Category).GetProperty("CategoryID") };
            tableMapping.RowType.Associations.Add(associationMapping);

            tableMapping = new TableMapping(typeof(Product)) { Name = "Products" };
            databaseMapping.Tables.Add(tableMapping);

            columnProperties = new[] { 
                typeof(Product).GetProperty("ProductID"), 
                typeof(Product).GetProperty("ProductName"),
                typeof(Product).GetProperty("CategoryID"), 
            };
            associationProperty = typeof(Product).GetProperty("Category");
            foreach (var property in columnProperties)
            {
                columnMapping = new ColumnMapping(property);
                tableMapping.RowType.Columns.Add(columnMapping);
            }
            associationMapping = new AssociationMapping(associationProperty);
            associationMapping.ThisMember = new[] { typeof(Product).GetProperty("CategoryID") };
            associationMapping.OtherMember = new[] { typeof(Category).GetProperty("CategoryID") };
            associationMapping.IsForeignKey = true;
            tableMapping.RowType.Associations.Add(associationMapping);
            var doc = DatabaseMappingSerializer.Serialize(databaseMapping);

            var mappingSource = XmlMappingSource.FromXml(doc.OuterXml);


            var model = mappingSource.GetModel(typeof(NorthwindDatabase));

            Assert.AreEqual(typeof(NorthwindDatabase), model.ContextType);
            Assert.AreEqual(typeof(NorthwindDatabase).Name, model.DatabaseName);

            var tables = model.GetTables().ToArray();
            Assert.AreEqual(2, tables.Length);

            var categoryTable = tables[0];
            var productTable = tables[1];
            Assert.AreEqual(5, categoryTable.RowType.DataMembers.Count);
            Assert.AreEqual(4, productTable.RowType.DataMembers.Count);

        }

    }
}
